<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:sch="http://purl.oclc.org/dsdl/schematron" version="1.0">
  <xsl:output indent="yes"/>
  <xsl:template match="/">
    <sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron"
      xml:lang="en">
      <sch:title>Schematron for <xsl:value-of select="@title"
        /></sch:title>
      <sch:ns prefix="cda" uri="urn:hl7-org:v3"/>
      <sch:ns prefix="sch" uri="http://purl.oclc.org/dsdl/schematron"/>
      <sch:p>This schematron has been created automatically from
        Trifolia workbench data</sch:p>
      <xsl:apply-templates select="tdb/templates/template"/>
    </sch:schema>
  </xsl:template>

  <xsl:template match="template">
    <sch:rule context="{@context}[cda:templateId = '{@OID}']">
      <sch:assert test="local-name() = &quot;{@context}&quot;">
        <xsl:text>The </xsl:text>
        <xsl:value-of select="title"/>
        <xsl:text> template (</xsl:text>
        <xsl:value-of select="@OID"/>
        <xsl:text>) applies only to </xsl:text>
        <xsl:value-of select="@context"/>
        <xsl:text> elements. </xsl:text>
      </sch:assert>
      <xsl:apply-templates select="constraint"/>
    </sch:rule>
  </xsl:template>
  <xsl:template match="constraint">
    <xsl:param name="context" select="'.'"/>
    <xsl:choose>
      <xsl:when test="@isBranch='true'">
        <branch><xsl:call-template name="constraint">
          <xsl:with-param name="context" select="$context"/>
        </xsl:call-template></branch>
      </xsl:when>
      <xsl:otherwise><xsl:call-template name="constraint">
        <xsl:with-param name="context" select="$context"/>
      </xsl:call-template></xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template name="constraint">
    <xsl:param name="context"/>
    <!-- what we count is either the context, or the child templates,
      depending on what's in containedTemplate -->
    <xsl:variable name="ctx">
      <xsl:value-of select="$context"/>
      <xsl:if test="substring($context,string-length($context),1)!='/'"
        >/</xsl:if>
      <xsl:value-of select="@context"/>
    </xsl:variable>
    <xsl:if test="@cardinality">
      <xsl:variable name="countedCtx">
        <xsl:choose>
          <xsl:when test="@containedTemplate">
            <xsl:text>.//*/cda:templateId[@root = "</xsl:text>
            <xsl:value-of select="@containedTemplate"/>
            <xsl:text>"]</xsl:text>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$ctx"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="@lower = @upper">
          <sch:assert test="count({$countedCtx})={@lower}"> The
              <xsl:call-template name="getName"/> appear only
              <xsl:value-of select="@lower"/> time(s). </sch:assert>
        </xsl:when>
        <xsl:when test="@upper = '*'">
          <sch:assert test="count({$countedCtx})&gt;={@lower}"> The
              <xsl:call-template name="getName"/> appear at least
              <xsl:value-of select="@lower"/> time(s). </sch:assert>
        </xsl:when>
        <xsl:otherwise>
          <sch:assert
            test="count({$countedCtx})&gt;={@lower} and count({$countedCtx})&lt;={@upper}"
            > The <xsl:call-template name="getName"/> appear at least
              <xsl:value-of select="@lower"/> time(s) and no more than
              <xsl:value-of select="@upper"/> time(s). </sch:assert>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
    <xsl:choose>
      <xsl:when test="@codeOrValue">
        <sch:assert test="{$ctx} = &quot;{@codeOrValue}&quot;">
          <xsl:text>The value of </xsl:text>
          <xsl:value-of select="$ctx"/>
          <xsl:text> </xsl:text>
          <xsl:value-of select="@businessConformance"/>
          <xsl:text> be </xsl:text>
          <xsl:value-of select="@codeOrValue"/>
          <xsl:text>. </xsl:text>
        </sch:assert>
      </xsl:when>
      <xsl:when test="@valueSetOID">
        <sch:assert
          test="{$ctx} = document(concat($valueSetService,&quot;?id=&quot;,@valueSetOID)//Concept/@code">
          <xsl:value-of select="$ctx"/>
          <xsl:text> </xsl:text>
          <xsl:value-of select="@valueConformance"/>
          <xsl:text> come from the value set </xsl:text>
          <xsl:value-of
            select="//valueset[@OID = current()/@valueSetOID]/valueSetName"/>
          <xsl:text> (</xsl:text>
          <xsl:value-of select="@valueSetOID"/>
          <xsl:text>).</xsl:text>
        </sch:assert>
      </xsl:when>
    </xsl:choose>
    <!-- TBD: Handle datatype -->
    <xsl:apply-templates select="constraint">
      <xsl:with-param name="context" select="$ctx"/>
    </xsl:apply-templates>
  </xsl:template>
  <xsl:template name="getName">
    <xsl:choose>
      <xsl:when test="@containedTemplate">
        <xsl:value-of
          select="//template[@OID = current()/@containedTemplate]/title"/>
        <xsl:text> template (</xsl:text>
        <xsl:value-of select="@containedTemplate"/>
        <xsl:text>) </xsl:text>
      </xsl:when>
      <xsl:when test="contains(@context,&quot;@&quot;)">
        <xsl:value-of select="@context"/>
        <xsl:text> attribute </xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="@context"/>
        <xsl:text> element </xsl:text>
      </xsl:otherwise>
    </xsl:choose>
    <xsl:value-of select="@businessConformance"/>
    <xsl:text> </xsl:text>
  </xsl:template>
</xsl:stylesheet>
